@iwonz/ywtc 0.0.0-stage → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (94) hide show
  1. package/.env.example +4 -0
  2. package/CHANGELOG.md +39 -0
  3. package/LICENSE +21 -0
  4. package/README.md +259 -2
  5. package/dist/adapters/confluence.d.ts +46 -0
  6. package/dist/adapters/confluence.js +187 -0
  7. package/dist/adapters/confluence.js.map +1 -0
  8. package/dist/adapters/factory.d.ts +3 -0
  9. package/dist/adapters/factory.js +11 -0
  10. package/dist/adapters/factory.js.map +1 -0
  11. package/dist/adapters/yandex.d.ts +45 -0
  12. package/dist/adapters/yandex.js +233 -0
  13. package/dist/adapters/yandex.js.map +1 -0
  14. package/dist/cli-arguments.d.ts +41 -0
  15. package/dist/cli-arguments.js +149 -0
  16. package/dist/cli-arguments.js.map +1 -0
  17. package/dist/cli.d.ts +2 -0
  18. package/dist/cli.js +180 -0
  19. package/dist/cli.js.map +1 -0
  20. package/dist/clients/confluence-cloud.d.ts +45 -0
  21. package/dist/clients/confluence-cloud.js +261 -0
  22. package/dist/clients/confluence-cloud.js.map +1 -0
  23. package/dist/clients/confluence-factory.d.ts +3 -0
  24. package/dist/clients/confluence-factory.js +8 -0
  25. package/dist/clients/confluence-factory.js.map +1 -0
  26. package/dist/clients/confluence.d.ts +42 -0
  27. package/dist/clients/confluence.js +286 -0
  28. package/dist/clients/confluence.js.map +1 -0
  29. package/dist/clients/yandex-wiki.d.ts +35 -0
  30. package/dist/clients/yandex-wiki.js +255 -0
  31. package/dist/clients/yandex-wiki.js.map +1 -0
  32. package/dist/config.d.ts +52 -0
  33. package/dist/config.js +177 -0
  34. package/dist/config.js.map +1 -0
  35. package/dist/content-model.d.ts +12 -0
  36. package/dist/content-model.js +416 -0
  37. package/dist/content-model.js.map +1 -0
  38. package/dist/conversion.d.ts +43 -0
  39. package/dist/conversion.js +450 -0
  40. package/dist/conversion.js.map +1 -0
  41. package/dist/doctor.d.ts +24 -0
  42. package/dist/doctor.js +45 -0
  43. package/dist/doctor.js.map +1 -0
  44. package/dist/domain.d.ts +202 -0
  45. package/dist/domain.js +18 -0
  46. package/dist/domain.js.map +1 -0
  47. package/dist/filesystem-export.d.ts +53 -0
  48. package/dist/filesystem-export.js +243 -0
  49. package/dist/filesystem-export.js.map +1 -0
  50. package/dist/graph.d.ts +13 -0
  51. package/dist/graph.js +121 -0
  52. package/dist/graph.js.map +1 -0
  53. package/dist/http.d.ts +26 -0
  54. package/dist/http.js +100 -0
  55. package/dist/http.js.map +1 -0
  56. package/dist/index.d.ts +24 -0
  57. package/dist/index.js +25 -0
  58. package/dist/index.js.map +1 -0
  59. package/dist/input.d.ts +4 -0
  60. package/dist/input.js +56 -0
  61. package/dist/input.js.map +1 -0
  62. package/dist/locators.d.ts +24 -0
  63. package/dist/locators.js +84 -0
  64. package/dist/locators.js.map +1 -0
  65. package/dist/logger.d.ts +7 -0
  66. package/dist/logger.js +28 -0
  67. package/dist/logger.js.map +1 -0
  68. package/dist/migrator.d.ts +53 -0
  69. package/dist/migrator.js +669 -0
  70. package/dist/migrator.js.map +1 -0
  71. package/dist/rate-limiter.d.ts +12 -0
  72. package/dist/rate-limiter.js +31 -0
  73. package/dist/rate-limiter.js.map +1 -0
  74. package/dist/report.d.ts +101 -0
  75. package/dist/report.js +106 -0
  76. package/dist/report.js.map +1 -0
  77. package/dist/state.d.ts +119 -0
  78. package/dist/state.js +201 -0
  79. package/dist/state.js.map +1 -0
  80. package/dist/types.d.ts +197 -0
  81. package/dist/types.js +2 -0
  82. package/dist/types.js.map +1 -0
  83. package/dist/updater.d.ts +24 -0
  84. package/dist/updater.js +92 -0
  85. package/dist/updater.js.map +1 -0
  86. package/dist/version.d.ts +1 -0
  87. package/dist/version.js +8 -0
  88. package/dist/version.js.map +1 -0
  89. package/dist/workspace.d.ts +29 -0
  90. package/dist/workspace.js +157 -0
  91. package/dist/workspace.js.map +1 -0
  92. package/docs/assets/readme-header.png +0 -0
  93. package/package.json +110 -4
  94. package/ywtc.config.example.yaml +52 -0
package/.env.example ADDED
@@ -0,0 +1,4 @@
1
+ # Secrets referenced by named profiles in ywtc.config.yaml
2
+ YANDEX_WIKI_TOKEN=
3
+ CONFLUENCE_TOKEN=
4
+ CONFLUENCE_EMAIL=
package/CHANGELOG.md ADDED
@@ -0,0 +1,39 @@
1
+ # Changelog
2
+
3
+ Notable changes to `ywtc` are documented in this file. Versions follow [Semantic Versioning](https://semver.org/).
4
+
5
+ ## [2.0.0](https://github.com/iwonz/ywtc/compare/v1.0.0...v2.0.0) (2026-10-15)
6
+
7
+
8
+ ### ⚠ BREAKING CHANGES
9
+
10
+ * use --destination, --scope, and state v2; require Node.js 24 and npm 11.5.1.
11
+ * migration now requires the migrate subcommand and explicit deployment settings.
12
+
13
+ ### Features
14
+
15
+ * generalize content transfer and static export ([a707f26](https://github.com/iwonz/ywtc/commit/a707f2670831c6c20277780bf02c651f920fbd28))
16
+ * ship ywtc v2 workspace and distribution ([1c4c8bd](https://github.com/iwonz/ywtc/commit/1c4c8bd9dc43ca1e0e36d6690019dae34b7dcfc8))
17
+
18
+
19
+ ### Documentation
20
+
21
+ * clarify migration quick start ([d09a306](https://github.com/iwonz/ywtc/commit/d09a306637367592842d0653d0a382e46a774fbe))
22
+ * document first npm release bootstrap ([0496ccb](https://github.com/iwonz/ywtc/commit/0496ccbc1ac82c97ca0f80a75ce082ee1ffbb7ad))
23
+ * simplify README cover framing ([708e0ac](https://github.com/iwonz/ywtc/commit/708e0ac7da6d063532962e61ba3e58c9b5993a5d))
24
+
25
+
26
+ ### Continuous Integration
27
+
28
+ * refresh GitHub Actions runtimes ([a6c33be](https://github.com/iwonz/ywtc/commit/a6c33be725ca2f5803e0cf7bd5277588f52b4afb))
29
+
30
+ ## [1.0.0] - 2026-10-14
31
+
32
+ ### Added
33
+
34
+ - Resumable migration of Yandex Wiki page trees to Confluence Data Center.
35
+ - YFM conversion, internal-link rewriting, attachments, images, tables, dynamic-grid snapshots, and readable degradation fallbacks.
36
+ - Automatic per-migration state, single-page mode, dry-run, rate controls, terminal progress, and HTML/JSON reports.
37
+ - Public documentation, release hygiene, Biome, Knip, tests, and the mandatory OpenSpec workflow.
38
+
39
+ [1.0.0]: https://github.com/iwonz/ywtc/releases/tag/v1.0.0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,260 @@
1
- # Temporary Holding Version
1
+ <p align="center">
2
+ <img src="docs/assets/readme-header.png" alt="Yandex Wiki and Confluence content moving through the ywtc pipeline" width="100%">
3
+ </p>
2
4
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
5
+ # ywtc
6
+
7
+ `ywtc` — CLI для контролируемого переноса страниц между Yandex Wiki и Confluence, а также экспорта в Markdown или автономный HTML. Утилита сохраняет структуру, ссылки и вложения, отмечает деградации, проверяет результат и продолжает прерванную операцию по state-файлу. Исходные данные и страницы назначения автоматически не удаляются.
8
+
9
+ Требуются Node.js `>=24` и npm `>=11.5.1`.
10
+
11
+ ## Возможности
12
+
13
+ | Что переносится | Результат |
14
+ | --- | --- |
15
+ | Страницы и иерархия | Одна страница, структурное поддерево или граф связанных страниц |
16
+ | Заголовки, текст, списки, цитаты, код, таблицы | Нативная разметка назначения, насколько это допускает формат |
17
+ | Внутренние ссылки и якоря | Переписываются на перенесённые страницы; внешние остаются внешними |
18
+ | Изображения и вложения | Потоковая передача с проверкой имени, размера и SHA-256 |
19
+ | Yandex notes, cuts, tabs и Grid | Ближайший нативный эквивалент; Grid становится статической таблицей |
20
+ | Confluence macros и resource identifiers | Сохраняются напрямую для same-vendor transfer либо преобразуются |
21
+ | Неподдерживаемые vendor-конструкции | Читаемый fallback и raw snapshot: attachment или файл в `_source/` |
22
+ | История, комментарии, пользователи, права, watchers | Не переносятся |
23
+
24
+ ## Минимальный сценарий
25
+
26
+ - [ ] Установите CLI: `npm install -g @iwonz/ywtc`.
27
+ - [ ] Создайте workspace: `ywtc init`.
28
+ - [ ] Заполните `~/.ywtc/ywtc.config.yaml` и секреты в `~/.ywtc/.env`.
29
+ - [ ] Проверьте доступ: `ywtc doctor --source <source> --destination <destination>`.
30
+ - [ ] Выполните dry-run: `ywtc migrate --source <source> --destination <destination> --dry-run`.
31
+ - [ ] Повторите команду без `--dry-run`.
32
+
33
+ ## Установка
34
+
35
+ ```bash
36
+ # npm
37
+ npm install -g @iwonz/ywtc
38
+
39
+ # без глобальной установки
40
+ npx @iwonz/ywtc@latest --version
41
+
42
+ # Homebrew
43
+ brew tap iwonz/ywtc https://github.com/iwonz/ywtc.git
44
+ brew install ywtc
45
+ ```
46
+
47
+ Проверить или установить обновление:
48
+
49
+ ```bash
50
+ ywtc update
51
+ ywtc update --install # только global npm или Homebrew
52
+ ywtc update --install --via brew
53
+ ```
54
+
55
+ ## Профили и workspace
56
+
57
+ Workspace выбирается в порядке `--workdir` → текущий каталог с `.ywtc-workspace.json` → `~/.ywtc`. Команда `init` идемпотентна и не перезаписывает существующие файлы:
58
+
59
+ ```text
60
+ ~/.ywtc/
61
+ ├── .ywtc-workspace.json
62
+ ├── .env # только секреты, mode 0600
63
+ ├── ywtc.config.yaml # подключения без секретов
64
+ └── .states/ # state, cache и HTML-отчёты
65
+ ```
66
+
67
+ Минимальная конфигурация двух подключений:
68
+
69
+ ```yaml
70
+ schemaVersion: 2
71
+ defaults:
72
+ timeoutMs: 30000
73
+ concurrency: 4
74
+
75
+ connections:
76
+ wiki-prod:
77
+ type: yandex-wiki
78
+ apiUrl: https://api.wiki.yandex.net/v1
79
+ webUrl: https://wiki.example.ru
80
+ authType: oauth
81
+ tokenEnv: YANDEX_WIKI_TOKEN
82
+ organization: {type: yandex360, id: organization-id}
83
+
84
+ confluence-prod:
85
+ type: confluence
86
+ deployment: data-center
87
+ baseUrl: https://confluence.example.ru/confluence
88
+ authType: pat
89
+ tokenEnv: CONFLUENCE_TOKEN
90
+ ```
91
+
92
+ ```dotenv
93
+ YANDEX_WIKI_TOKEN=
94
+ CONFLUENCE_TOKEN=
95
+ # Для Confluence Cloud:
96
+ CONFLUENCE_EMAIL=
97
+ ```
98
+
99
+ Полный шаблон с сетевыми лимитами находится в [`ywtc.config.example.yaml`](ywtc.config.example.yaml). Значения process environment имеют приоритет над `.env`. Секреты проверяются только для профилей, участвующих в текущей операции.
100
+
101
+ ## Как получить токены
102
+
103
+ ### Yandex Wiki
104
+
105
+ - [ ] Создайте приложение в [Яндекс OAuth](https://oauth.yandex.ru/) для доступа к API.
106
+ - [ ] Выдайте приложению права Wiki на чтение; для destination также нужны права записи.
107
+ - [ ] Получите OAuth-токен пользователя, имеющего доступ к нужным страницам. Для федеративного пользователя Yandex Cloud можно использовать IAM-токен и `authType: iam`.
108
+ - [ ] Найдите ID организации в **Yandex Tracker → Администрирование → Организации**.
109
+ - [ ] Укажите `organization.type: yandex360` для Яндекс 360 либо `cloud` для Cloud Organization.
110
+ - [ ] Сохраните токен в env-переменной, указанной в `tokenEnv`.
111
+
112
+ ### Confluence Data Center
113
+
114
+ - [ ] Откройте **Avatar → Settings → Personal access tokens → Create token**.
115
+ - [ ] Создайте PAT и сохраните его в env-переменной из `tokenEnv`.
116
+ - [ ] Используйте `deployment: data-center` и `authType: pat`.
117
+ - [ ] Убедитесь, что пользователь может читать source и создавать/изменять страницы и вложения destination.
118
+
119
+ ### Confluence Cloud
120
+
121
+ - [ ] Создайте [Atlassian API token](https://id.atlassian.com/manage-profile/security/api-tokens).
122
+ - [ ] Используйте `deployment: cloud`, `authType: api-token`, `tokenEnv` и `emailEnv`.
123
+ - [ ] Сохраните API token и email Atlassian-аккаунта в соответствующих env-переменных.
124
+ - [ ] Проверьте доступ аккаунта к source/destination space.
125
+
126
+ ## Направления и совместимость
127
+
128
+ | Source | Destination | Поддержка |
129
+ | --- | --- | --- |
130
+ | Yandex Wiki | Confluence | Да |
131
+ | Yandex Wiki | Yandex Wiki | Да, включая другой профиль/инстанс |
132
+ | Confluence | Yandex Wiki | Да |
133
+ | Confluence | Confluence | Да, включая другой профиль/инстанс |
134
+ | Yandex Wiki или Confluence | Markdown | Да |
135
+ | Yandex Wiki или Confluence | статический HTML | Да |
136
+
137
+ | Система | Поддерживаемый контракт | Авторизация |
138
+ | --- | --- | --- |
139
+ | Yandex Wiki | Public API v1; tolerant parsing новых необязательных полей | OAuth или пользовательский IAM; `X-Org-Id`/`X-Cloud-Org-Id` |
140
+ | Confluence Data Center | 7.9+ без искусственной верхней границы; capabilities проверяются до записи | Bearer PAT |
141
+ | Confluence Cloud | Текущий публичный REST v2 для страниц и v1 для attachments | Email + API token |
142
+
143
+ Confluence Server, Data Center Basic Auth и OAuth app-flow пока не поддерживаются. Совместимость определяется preflight-проверкой используемых API/capabilities, а не обещанием для каждой patch-версии.
144
+
145
+ ## Параметры `migrate`
146
+
147
+ ```text
148
+ ywtc migrate --source <locator> --destination <locator|directory> [options]
149
+ ```
150
+
151
+ | Параметр | Обязателен | Значения / default | Назначение |
152
+ | --- | --- | --- | --- |
153
+ | `--source <value>` | Да | URL, page ID или slug | Исходная страница |
154
+ | `--destination <value>` | Да | URL, page ID, slug или каталог | Родительская страница либо каталог экспорта |
155
+ | `--source-profile <name>` | Иногда | имя из `connections` | Нужен для неоднозначного короткого ID/slug |
156
+ | `--destination-profile <name>` | Иногда | имя из `connections` | То же для удалённой destination |
157
+ | `--scope <mode>` | Нет | `page`, `subtree` (default), `linked` | Граница выбора страниц |
158
+ | `--format <format>` | Для каталога | `markdown`, `html` | Однозначно включает файловый экспорт |
159
+ | `--archive` | Нет | только с `--format` | Оставляет каталог и создаёт ZIP рядом |
160
+ | `--dry-run` | Нет | `false` | Полный discovery/план без destination writes |
161
+ | `--workdir <path>` | Нет | marker CWD или `~/.ywtc` | Выбирает workspace |
162
+ | `--state <path>` | Нет | `.states/<automatic-id>.json` | Явный state внутри workspace |
163
+ | `--fresh` | Нет | `false` | Не использует mappings; live-run сохраняет backup state |
164
+ | `--concurrency <n>` | Нет | `1..64`, config default `4` | Параллельность оркестрации; профильные лимиты действуют отдельно |
165
+
166
+ Полный URL автоматически сопоставляется с профилем по нормализованному base URL. Для короткого ID/slug профиль выбирается автоматически только при единственном подходящем подключении; иначе CLI перечисляет допустимые имена. Каталог считается файловой destination только вместе с `--format`.
167
+
168
+ ### Scope
169
+
170
+ - `page` — только исходная страница.
171
+ - `subtree` — страница и все структурные потомки; режим по умолчанию.
172
+ - `linked` — детерминированный BFS по внутренним ссылкам и page/include references до фиксированной точки. Циклы безопасно завершаются, страница обрабатывается один раз. Внешние и недоступные ссылки не обходятся и отражаются в отчёте.
173
+
174
+ ## Частые примеры
175
+
176
+ ```bash
177
+ # Связанные страницы Yandex Wiki → Confluence
178
+ ywtc migrate \
179
+ --source https://wiki.example.ru/team/start \
180
+ --destination https://confluence.example.ru/pages/viewpage.action?pageId=123 \
181
+ --scope linked
182
+
183
+ # Confluence → Yandex Wiki по коротким идентификаторам
184
+ ywtc migrate \
185
+ --source-profile confluence-prod --source 123456 \
186
+ --destination-profile wiki-prod --destination team/archive \
187
+ --scope subtree
188
+
189
+ # Одна страница без потомков
190
+ ywtc migrate --source-profile wiki-prod --source team/start \
191
+ --destination-profile confluence-prod --destination 123 --scope page
192
+
193
+ # Автономный HTML-сайт и ZIP
194
+ ywtc migrate --source-profile confluence-prod --source 123456 \
195
+ --destination ./exports/knowledge-base --format html --scope linked --archive
196
+
197
+ # Markdown-экспорт в отдельном workspace
198
+ ywtc migrate --workdir ./migration --source-profile wiki-prod --source team/start \
199
+ --destination ./export --format markdown --dry-run
200
+ ```
201
+
202
+ `doctor` принимает те же `source`, `destination`, profile, `scope` и `format`; с endpoints выполняет только read-only capability-preflight. Без endpoints проверяет workspace, конфигурацию и все секреты.
203
+
204
+ ## Файловый экспорт
205
+
206
+ Markdown создаёт `index.md`, `pages/`, `attachments/`, manifest `.ywtc-export.json` и, при деградациях, `_source/`. HTML создаёт автономный адаптивный сайт с теми же данными и локальным `assets/site.css`; он работает через `file://` и на обычном static hosting без CDN/runtime.
207
+
208
+ Экспорт строится в staging-каталоге. Существующий каталог заменяется только при совпадающем ywtc manifest; предыдущая версия сохраняется как timestamped backup. ZIP не перезаписывает уже существующий архив.
209
+
210
+ ## State, отчёты и повторный запуск
211
+
212
+ Автоматический state ID строится из канонических профилей и ID source/destination; форма URL/slug/ID и `scope` на него не влияют. Поэтому одна и та же пара endpoints возобновляет один state, а разные пары получают разные файлы.
213
+
214
+ - Повторный запуск обновляет только сопоставленные объекты и не создаёт дубликаты.
215
+ - Страница, изменённая вручную после прошлого запуска, получает `conflict` и не перезаписывается.
216
+ - `--fresh` начинает с чистых mappings; live-run сохраняет прежний state как backup и может создать новые страницы.
217
+ - State schema v1 не мигрируется автоматически и остаётся нетронутой.
218
+ - SIGINT/SIGTERM останавливает постановку новых задач, сохраняет state/report и возвращает `130`/`143`.
219
+ - Каждый запуск создаёт `.states/reports/<run-id>/index.html` и `report.json`: направление, дерево, link graph, циклы, вложения, размеры, деградации, ошибки и side-by-side preview.
220
+
221
+ Коды выхода: `0` — завершено; `1` — partial/ошибка verification; `2` — usage/config/preflight; `130`/`143` — остановка сигналом.
222
+
223
+ ## Переход на 2.0
224
+
225
+ Обратной совместимости с предварительным CLI и state v1 нет:
226
+
227
+ | Было | Стало |
228
+ | --- | --- |
229
+ | `--target <value>` | `--destination <value>` |
230
+ | `--single-page` | `--scope page` |
231
+ | Один набор env-подключений | Именованные подключения в `ywtc.config.yaml`; `.env` содержит только секреты |
232
+ | State schema v1 | Новый автоматический provider-neutral state v2 |
233
+
234
+ Старые флаги отклоняются с точной подсказкой. Для переноса создайте новый workspace или сохраните старые state-файлы отдельно и выполните `ywtc init`.
235
+
236
+ ## Разработка
237
+
238
+ ```bash
239
+ git clone https://github.com/iwonz/ywtc.git
240
+ cd ywtc
241
+ npm ci
242
+ npm run workspace:init
243
+ npm run check
244
+ ```
245
+
246
+ `npm run check` запускает release/hygiene checks, аудит production-зависимостей (high/critical), TypeScript, Biome, Knip, тесты, сборку, проверку устанавливаемого tarball и строгую OpenSpec-валидацию. Изменения оформляются полным OpenSpec-циклом согласно [`AGENTS.md`](AGENTS.md).
247
+
248
+ ## Первый релиз (для сопровождающего)
249
+
250
+ Обычные релизы формирует Release Please из Conventional Commits. До первого релиза один раз:
251
+
252
+ - [ ] Установите npm `>=11.15`, выполните `npm login` и проверьте владельца: `npm whoami` должен вернуть `iwonz`.
253
+ - [ ] Опубликуйте минимальный пакет с интерактивной 2FA: `npm run release:bootstrap`. OTP не записывайте в команду, файл или CI.
254
+ - [ ] Свяжите пакет с workflow: `npm trust github @iwonz/ywtc --file release.yml --repo iwonz/ywtc --allow-publish`.
255
+ - [ ] В GitHub откройте **Settings → Actions → General → Workflow permissions** и включите **Allow GitHub Actions to create and approve pull requests**. Настройка действует на workflows репозитория; фактические возможности всё равно ограничены `permissions` каждого job.
256
+ - [ ] Перезапустите `CI and Release`, проверьте Release Please PR для `2.0.0` и слейте его. Workflow опубликует npm-пакет с provenance, GitHub Release и проверенную Homebrew-формулу.
257
+
258
+ Требования и синтаксис: [npm trusted publishing](https://docs.npmjs.com/trusted-publishers/) и [`npm trust`](https://docs.npmjs.com/cli/v11/commands/npm-trust/). Версии `package.json`, lock-файла и changelog вручную не меняются.
259
+
260
+ Лицензия: [MIT](LICENSE).
@@ -0,0 +1,46 @@
1
+ import type { ConfluenceConnectionProfile } from '../config.js';
2
+ import type { AdapterCapabilities, DestinationAdapter, DestinationContainer, DestinationPage, PageReference, SourceAdapter, SourcePage, SourceResource, UploadedResource } from '../domain.js';
3
+ import type { ConfluenceApi } from '../types.js';
4
+ export declare class ConfluenceAdapter implements SourceAdapter, DestinationAdapter {
5
+ readonly profile: ConfluenceConnectionProfile;
6
+ private readonly client;
7
+ readonly kind: "confluence";
8
+ readonly capabilities: AdapterCapabilities;
9
+ constructor(profile: ConfluenceConnectionProfile, client: ConfluenceApi);
10
+ preflight(): Promise<{
11
+ product: string;
12
+ version?: string;
13
+ warnings: string[];
14
+ }>;
15
+ resolvePage(locator: string): Promise<SourcePage>;
16
+ getPage(id: string): Promise<SourcePage>;
17
+ getDescendants(page: SourcePage): Promise<SourcePage[]>;
18
+ resolveReference(from: SourcePage, reference: PageReference): Promise<SourcePage | undefined>;
19
+ listResources(page: SourcePage): Promise<SourceResource[]>;
20
+ downloadResource(resource: SourceResource, destination: string): Promise<import("../types.js").DownloadedFile>;
21
+ resolveContainer(locator: string): Promise<DestinationContainer>;
22
+ findChild(container: DestinationContainer | DestinationPage, title: string): Promise<DestinationPage | undefined>;
23
+ createPage(input: {
24
+ container: DestinationContainer | DestinationPage;
25
+ title: string;
26
+ body: string;
27
+ }): Promise<DestinationPage>;
28
+ updatePage(input: {
29
+ page: DestinationPage;
30
+ title: string;
31
+ body: string;
32
+ expectedFingerprint?: string;
33
+ }): Promise<DestinationPage>;
34
+ uploadResource(input: {
35
+ page: DestinationPage;
36
+ name: string;
37
+ filePath: string;
38
+ size?: number;
39
+ mimeType?: string;
40
+ existingId?: string;
41
+ }): Promise<UploadedResource>;
42
+ listUploadedResources(page: DestinationPage): Promise<UploadedResource[]>;
43
+ verifyPage(page: DestinationPage): Promise<DestinationPage>;
44
+ renderPageReference(page: DestinationPage, label: string, anchor?: string): string;
45
+ renderResourceReference(resource: UploadedResource, label: string, image: boolean): string;
46
+ }
@@ -0,0 +1,187 @@
1
+ import { createHash } from 'node:crypto';
2
+ import { createReadStream } from 'node:fs';
3
+ import { extractPageReferences } from '../content-model.js';
4
+ const capabilities = {
5
+ readPages: true,
6
+ readHierarchy: true,
7
+ readResources: true,
8
+ writePages: true,
9
+ writeResources: true,
10
+ verifyWrites: true,
11
+ };
12
+ function canonical(profile, id) {
13
+ return `${profile.name}:confluence:${id}`;
14
+ }
15
+ function fingerprint(page) {
16
+ return createHash('sha256').update(`${page.title}\0${page.body?.storage?.value ?? ''}\0${page.version?.number ?? ''}`).digest('hex');
17
+ }
18
+ function sourcePage(profile, client, page) {
19
+ const rawContent = page.body?.storage?.value ?? '';
20
+ return {
21
+ provider: 'confluence',
22
+ profile: profile.name,
23
+ id: page.id,
24
+ canonicalId: canonical(profile, page.id),
25
+ title: page.title,
26
+ locator: page.id,
27
+ url: client.pageWebUrl(page),
28
+ ...(page.ancestors?.at(-1)?.id ? { parentId: page.ancestors.at(-1).id } : {}),
29
+ space: page.space.key,
30
+ rawContent,
31
+ rawFormat: 'confluence-storage',
32
+ ...(page.version?.number ? { version: String(page.version.number) } : {}),
33
+ references: extractPageReferences(rawContent, 'confluence-storage'),
34
+ };
35
+ }
36
+ function destinationPage(profile, client, page) {
37
+ return {
38
+ provider: 'confluence',
39
+ profile: profile.name,
40
+ id: page.id,
41
+ canonicalId: canonical(profile, page.id),
42
+ title: page.title,
43
+ url: client.pageWebUrl(page),
44
+ locator: page.id,
45
+ space: page.space.key,
46
+ ...(page.version?.number ? { version: String(page.version.number) } : {}),
47
+ fingerprint: fingerprint(page),
48
+ contentLength: Buffer.byteLength(page.body?.storage?.value ?? ''),
49
+ };
50
+ }
51
+ export class ConfluenceAdapter {
52
+ profile;
53
+ client;
54
+ kind = 'confluence';
55
+ capabilities = capabilities;
56
+ constructor(profile, client) {
57
+ this.profile = profile;
58
+ this.client = client;
59
+ }
60
+ async preflight() {
61
+ const info = await this.client.preflight?.();
62
+ return { product: info?.product ?? 'Confluence', ...(info?.version ? { version: info.version } : {}), warnings: [] };
63
+ }
64
+ async resolvePage(locator) {
65
+ return sourcePage(this.profile, this.client, await this.client.resolveTarget(locator));
66
+ }
67
+ async getPage(id) {
68
+ return sourcePage(this.profile, this.client, await this.client.getPage(id));
69
+ }
70
+ async getDescendants(page) {
71
+ return (await this.client.getDescendants(page.id)).map((item) => sourcePage(this.profile, this.client, item));
72
+ }
73
+ async resolveReference(from, reference) {
74
+ if (reference.kind !== 'page')
75
+ return undefined;
76
+ const href = reference.href ?? '';
77
+ if (href.startsWith('confluence-page:'))
78
+ return this.getPage(href.slice('confluence-page:'.length));
79
+ if (href.startsWith('page:')) {
80
+ const value = href.slice('page:'.length);
81
+ if (/^\d+$/.test(value))
82
+ return this.getPage(value);
83
+ const found = await this.client.findPageByTitle(from.space ?? '', value);
84
+ return found ? sourcePage(this.profile, this.client, await this.client.getPage(found.id)) : undefined;
85
+ }
86
+ if (reference.pageTitle) {
87
+ const referencedSpace = reference.href?.includes(':') ? reference.href.split(':', 1)[0] : undefined;
88
+ const found = await this.client.findPageByTitle(referencedSpace || from.space || '', reference.pageTitle);
89
+ return found ? sourcePage(this.profile, this.client, await this.client.getPage(found.id)) : undefined;
90
+ }
91
+ if (/^(?:https?:\/\/|\/)|viewpage\.action|\/(?:pages|spaces)\//i.test(href)) {
92
+ const url = new URL(href, `${this.profile.baseUrl}/`);
93
+ if (url.origin !== new URL(this.profile.baseUrl).origin)
94
+ return undefined;
95
+ return sourcePage(this.profile, this.client, await this.client.resolveTarget(url.toString()));
96
+ }
97
+ const [space, title] = href.includes(':') ? href.split(':', 2) : [from.space ?? '', href];
98
+ if (!title)
99
+ return undefined;
100
+ const found = await this.client.findPageByTitle(space ?? '', title);
101
+ return found ? sourcePage(this.profile, this.client, await this.client.getPage(found.id)) : undefined;
102
+ }
103
+ async listResources(page) {
104
+ return (await this.client.listAttachments(page.id)).map((attachment) => ({
105
+ provider: 'confluence',
106
+ id: attachment.id,
107
+ pageId: page.id,
108
+ name: attachment.title,
109
+ ...(attachment.extensions?.fileSize !== undefined ? { size: attachment.extensions.fileSize } : {}),
110
+ ...(attachment.metadata?.mediaType ? { mimeType: attachment.metadata.mediaType } : {}),
111
+ ...(attachment._links?.download ? { downloadUrl: attachment._links.download } : {}),
112
+ kind: attachment.metadata?.mediaType?.startsWith('image/') ? 'image' : 'attachment',
113
+ metadata: { attachment },
114
+ }));
115
+ }
116
+ downloadResource(resource, destination) {
117
+ return this.client.downloadAttachment(resource.pageId, resource.metadata?.attachment, destination);
118
+ }
119
+ async resolveContainer(locator) {
120
+ const page = await this.client.resolveTarget(locator);
121
+ return {
122
+ provider: 'confluence', profile: this.profile.name, id: page.id, canonicalId: canonical(this.profile, page.id),
123
+ title: page.title, url: this.client.pageWebUrl(page), space: page.space.key, locator: page.id,
124
+ };
125
+ }
126
+ async findChild(container, title) {
127
+ const space = container.space;
128
+ if (!space)
129
+ return undefined;
130
+ const found = await this.client.findPageByTitle(space, title);
131
+ if (!found)
132
+ return undefined;
133
+ return destinationPage(this.profile, this.client, await this.client.getPage(found.id));
134
+ }
135
+ async createPage(input) {
136
+ const space = input.container.space;
137
+ if (!space)
138
+ throw new Error(`Confluence destination ${input.container.id} is missing a space key`);
139
+ return destinationPage(this.profile, this.client, await this.client.createPage({
140
+ spaceKey: space, parentId: input.container.id, title: input.title, storage: input.body,
141
+ }));
142
+ }
143
+ async updatePage(input) {
144
+ if (input.expectedFingerprint) {
145
+ const current = destinationPage(this.profile, this.client, await this.client.getPage(input.page.id));
146
+ if (current.fingerprint !== input.expectedFingerprint)
147
+ throw new Error(`Destination conflict for Confluence page ${input.page.id}: content changed since the last verified run`);
148
+ }
149
+ return destinationPage(this.profile, this.client, await this.client.updatePage({ pageId: input.page.id, title: input.title, storage: input.body }));
150
+ }
151
+ async uploadResource(input) {
152
+ const uploaded = await this.client.uploadAttachment({
153
+ pageId: input.page.id,
154
+ filename: input.name,
155
+ file: createReadStream(input.filePath),
156
+ ...(input.size !== undefined ? { contentLength: input.size } : {}),
157
+ ...(input.mimeType ? { mimeType: input.mimeType } : {}),
158
+ ...(input.existingId ? { existingAttachmentId: input.existingId } : {}),
159
+ });
160
+ return {
161
+ id: uploaded.id,
162
+ name: uploaded.title,
163
+ ...(uploaded.extensions?.fileSize !== undefined ? { size: uploaded.extensions.fileSize } : {}),
164
+ ...(uploaded._links?.download ? { url: uploaded._links.download } : {}),
165
+ };
166
+ }
167
+ async listUploadedResources(page) {
168
+ return (await this.client.listAttachments(page.id)).map((attachment) => ({
169
+ id: attachment.id,
170
+ name: attachment.title,
171
+ ...(attachment.extensions?.fileSize !== undefined ? { size: attachment.extensions.fileSize } : {}),
172
+ ...(attachment._links?.download ? { url: attachment._links.download } : {}),
173
+ }));
174
+ }
175
+ async verifyPage(page) {
176
+ return destinationPage(this.profile, this.client, await this.client.getPage(page.id));
177
+ }
178
+ renderPageReference(page, label, anchor) {
179
+ return `<ac:link${anchor ? ` ac:anchor="${anchor}"` : ''}><ri:page ri:content-title="${page.title}"/><ac:link-body>${label}</ac:link-body></ac:link>`;
180
+ }
181
+ renderResourceReference(resource, label, image) {
182
+ return image
183
+ ? `<ac:image ac:alt="${label}"><ri:attachment ri:filename="${resource.name}"/></ac:image>`
184
+ : `<ac:link><ri:attachment ri:filename="${resource.name}"/><ac:plain-text-link-body><![CDATA[${label}]]></ac:plain-text-link-body></ac:link>`;
185
+ }
186
+ }
187
+ //# sourceMappingURL=confluence.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"confluence.js","sourceRoot":"","sources":["../../src/adapters/confluence.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,UAAU,EAAC,MAAM,aAAa,CAAC;AACvC,OAAO,EAAC,gBAAgB,EAAC,MAAM,SAAS,CAAC;AAEzC,OAAO,EAAC,qBAAqB,EAAC,MAAM,qBAAqB,CAAC;AAc1D,MAAM,YAAY,GAAwB;IACxC,SAAS,EAAE,IAAI;IACf,aAAa,EAAE,IAAI;IACnB,aAAa,EAAE,IAAI;IACnB,UAAU,EAAE,IAAI;IAChB,cAAc,EAAE,IAAI;IACpB,YAAY,EAAE,IAAI;CACnB,CAAC;AAEF,SAAS,SAAS,CAAC,OAAoC,EAAE,EAAU;IACjE,OAAO,GAAG,OAAO,CAAC,IAAI,eAAe,EAAE,EAAE,CAAC;AAC5C,CAAC;AAED,SAAS,WAAW,CAAC,IAAoB;IACvC,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,KAAK,IAAI,CAAC,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,EAAE,KAAK,IAAI,CAAC,OAAO,EAAE,MAAM,IAAI,EAAE,EAAE,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AACvI,CAAC;AAED,SAAS,UAAU,CAAC,OAAoC,EAAE,MAAqB,EAAE,IAAoB;IACnG,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,EAAE,CAAC;IACnD,OAAO;QACL,QAAQ,EAAE,YAAY;QACtB,OAAO,EAAE,OAAO,CAAC,IAAI;QACrB,EAAE,EAAE,IAAI,CAAC,EAAE;QACX,WAAW,EAAE,SAAS,CAAC,OAAO,EAAE,IAAI,CAAC,EAAE,CAAC;QACxC,KAAK,EAAE,IAAI,CAAC,KAAK;QACjB,OAAO,EAAE,IAAI,CAAC,EAAE;QAChB,GAAG,EAAE,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC;QAC5B,GAAG,CAAC,IAAI,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAC,QAAQ,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC,CAAC,CAAE,CAAC,EAAE,EAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QAC5E,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,GAAG;QACrB,UAAU;QACV,SAAS,EAAE,oBAAoB;QAC/B,GAAG,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC,EAAC,OAAO,EAAE,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,EAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QACvE,UAAU,EAAE,qBAAqB,CAAC,UAAU,EAAE,oBAAoB,CAAC;KACpE,CAAC;AACJ,CAAC;AAED,SAAS,eAAe,CAAC,OAAoC,EAAE,MAAqB,EAAE,IAAoB;IACxG,OAAO;QACL,QAAQ,EAAE,YAAY;QACtB,OAAO,EAAE,OAAO,CAAC,IAAI;QACrB,EAAE,EAAE,IAAI,CAAC,EAAE;QACX,WAAW,EAAE,SAAS,CAAC,OAAO,EAAE,IAAI,CAAC,EAAE,CAAC;QACxC,KAAK,EAAE,IAAI,CAAC,KAAK;QACjB,GAAG,EAAE,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC;QAC5B,OAAO,EAAE,IAAI,CAAC,EAAE;QAChB,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,GAAG;QACrB,GAAG,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC,EAAC,OAAO,EAAE,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,EAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QACvE,WAAW,EAAE,WAAW,CAAC,IAAI,CAAC;QAC9B,aAAa,EAAE,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,EAAE,CAAC;KAClE,CAAC;AACJ,CAAC;AAED,MAAM,OAAO,iBAAiB;IAIA;IAAuD;IAH1E,IAAI,GAAG,YAAqB,CAAC;IAC7B,YAAY,GAAG,YAAY,CAAC;IAErC,YAA4B,OAAoC,EAAmB,MAAqB;QAA5E,YAAO,GAAP,OAAO,CAA6B;QAAmB,WAAM,GAAN,MAAM,CAAe;IAAG,CAAC;IAE5G,KAAK,CAAC,SAAS;QACb,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,EAAE,CAAC;QAC7C,OAAO,EAAC,OAAO,EAAE,IAAI,EAAE,OAAO,IAAI,YAAY,EAAE,GAAG,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC,EAAC,OAAO,EAAE,IAAI,CAAC,OAAO,EAAC,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,QAAQ,EAAE,EAAE,EAAC,CAAC;IACnH,CAAC;IAED,KAAK,CAAC,WAAW,CAAC,OAAe;QAC/B,OAAO,UAAU,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,MAAM,EAAE,MAAM,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,CAAC;IACzF,CAAC;IAED,KAAK,CAAC,OAAO,CAAC,EAAU;QACtB,OAAO,UAAU,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,MAAM,EAAE,MAAM,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC;IAC9E,CAAC;IAED,KAAK,CAAC,cAAc,CAAC,IAAgB;QACnC,OAAO,CAAC,MAAM,IAAI,CAAC,MAAM,CAAC,cAAc,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,CAAC;IAChH,CAAC;IAED,KAAK,CAAC,gBAAgB,CAAC,IAAgB,EAAE,SAAwB;QAC/D,IAAI,SAAS,CAAC,IAAI,KAAK,MAAM;YAAE,OAAO,SAAS,CAAC;QAChD,MAAM,IAAI,GAAG,SAAS,CAAC,IAAI,IAAI,EAAE,CAAC;QAClC,IAAI,IAAI,CAAC,UAAU,CAAC,kBAAkB,CAAC;YAAE,OAAO,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,kBAAkB,CAAC,MAAM,CAAC,CAAC,CAAC;QACpG,IAAI,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;YAC7B,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;YACzC,IAAI,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC;gBAAE,OAAO,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;YACpD,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,eAAe,CAAC,IAAI,CAAC,KAAK,IAAI,EAAE,EAAE,KAAK,CAAC,CAAC;YACzE,OAAO,KAAK,CAAC,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,MAAM,EAAE,MAAM,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;QACxG,CAAC;QACD,IAAI,SAAS,CAAC,SAAS,EAAE,CAAC;YACxB,MAAM,eAAe,GAAG,SAAS,CAAC,IAAI,EAAE,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;YACpG,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,eAAe,CAAC,eAAe,IAAI,IAAI,CAAC,KAAK,IAAI,EAAE,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;YAC1G,OAAO,KAAK,CAAC,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,MAAM,EAAE,MAAM,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;QACxG,CAAC;QACD,IAAI,4DAA4D,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;YAC5E,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,IAAI,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,GAAG,CAAC,CAAC;YACtD,IAAI,GAAG,CAAC,MAAM,KAAK,IAAI,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,MAAM;gBAAE,OAAO,SAAS,CAAC;YAC1E,OAAO,UAAU,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,MAAM,EAAE,MAAM,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC;QAChG,CAAC;QACD,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,IAAI,EAAE,EAAE,IAAI,CAAC,CAAC;QAC1F,IAAI,CAAC,KAAK;YAAE,OAAO,SAAS,CAAC;QAC7B,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,eAAe,CAAC,KAAK,IAAI,EAAE,EAAE,KAAK,CAAC,CAAC;QACpE,OAAO,KAAK,CAAC,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,MAAM,EAAE,MAAM,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IACxG,CAAC;IAED,KAAK,CAAC,aAAa,CAAC,IAAgB;QAClC,OAAO,CAAC,MAAM,IAAI,CAAC,MAAM,CAAC,eAAe,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC;YACvE,QAAQ,EAAE,YAAqB;YAC/B,EAAE,EAAE,UAAU,CAAC,EAAE;YACjB,MAAM,EAAE,IAAI,CAAC,EAAE;YACf,IAAI,EAAE,UAAU,CAAC,KAAK;YACtB,GAAG,CAAC,UAAU,CAAC,UAAU,EAAE,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,EAAC,IAAI,EAAE,UAAU,CAAC,UAAU,CAAC,QAAQ,EAAC,CAAC,CAAC,CAAC,EAAE,CAAC;YAChG,GAAG,CAAC,UAAU,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC,CAAC,EAAC,QAAQ,EAAE,UAAU,CAAC,QAAQ,CAAC,SAAS,EAAC,CAAC,CAAC,CAAC,EAAE,CAAC;YACpF,GAAG,CAAC,UAAU,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC,CAAC,EAAC,WAAW,EAAE,UAAU,CAAC,MAAM,CAAC,QAAQ,EAAC,CAAC,CAAC,CAAC,EAAE,CAAC;YACjF,IAAI,EAAE,UAAU,CAAC,QAAQ,EAAE,SAAS,EAAE,UAAU,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,OAAgB,CAAC,CAAC,CAAC,YAAqB;YACrG,QAAQ,EAAE,EAAC,UAAU,EAAC;SACvB,CAAC,CAAC,CAAC;IACN,CAAC;IAED,gBAAgB,CAAC,QAAwB,EAAE,WAAmB;QAC5D,OAAO,IAAI,CAAC,MAAM,CAAC,kBAAkB,CAAC,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC,QAAQ,EAAE,UAAkC,EAAE,WAAW,CAAC,CAAC;IAC7H,CAAC;IAED,KAAK,CAAC,gBAAgB,CAAC,OAAe;QACpC,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC;QACtD,OAAO;YACL,QAAQ,EAAE,YAAY,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,EAAE,IAAI,CAAC,EAAE,EAAE,WAAW,EAAE,SAAS,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,EAAE,CAAC;YAC9G,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,GAAG,EAAE,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,GAAG,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE;SAC9F,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,SAAS,CAAC,SAAiD,EAAE,KAAa;QAC9E,MAAM,KAAK,GAAG,SAAS,CAAC,KAAK,CAAC;QAC9B,IAAI,CAAC,KAAK;YAAE,OAAO,SAAS,CAAC;QAC7B,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,eAAe,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;QAC9D,IAAI,CAAC,KAAK;YAAE,OAAO,SAAS,CAAC;QAC7B,OAAO,eAAe,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,MAAM,EAAE,MAAM,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC;IACzF,CAAC;IAED,KAAK,CAAC,UAAU,CAAC,KAAuF;QACtG,MAAM,KAAK,GAAG,KAAK,CAAC,SAAS,CAAC,KAAK,CAAC;QACpC,IAAI,CAAC,KAAK;YAAE,MAAM,IAAI,KAAK,CAAC,0BAA0B,KAAK,CAAC,SAAS,CAAC,EAAE,yBAAyB,CAAC,CAAC;QACnG,OAAO,eAAe,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,MAAM,EAAE,MAAM,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC;YAC7E,QAAQ,EAAE,KAAK,EAAE,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC,EAAE,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,OAAO,EAAE,KAAK,CAAC,IAAI;SACvF,CAAC,CAAC,CAAC;IACN,CAAC;IAED,KAAK,CAAC,UAAU,CAAC,KAAyF;QACxG,IAAI,KAAK,CAAC,mBAAmB,EAAE,CAAC;YAC9B,MAAM,OAAO,GAAG,eAAe,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,MAAM,EAAE,MAAM,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;YACrG,IAAI,OAAO,CAAC,WAAW,KAAK,KAAK,CAAC,mBAAmB;gBAAE,MAAM,IAAI,KAAK,CAAC,4CAA4C,KAAK,CAAC,IAAI,CAAC,EAAE,+CAA+C,CAAC,CAAC;QACnL,CAAC;QACD,OAAO,eAAe,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,MAAM,EAAE,MAAM,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,EAAC,MAAM,EAAE,KAAK,CAAC,IAAI,CAAC,EAAE,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,OAAO,EAAE,KAAK,CAAC,IAAI,EAAC,CAAC,CAAC,CAAC;IACpJ,CAAC;IAED,KAAK,CAAC,cAAc,CAAC,KAAqH;QACxI,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,gBAAgB,CAAC;YAClD,MAAM,EAAE,KAAK,CAAC,IAAI,CAAC,EAAE;YACrB,QAAQ,EAAE,KAAK,CAAC,IAAI;YACpB,IAAI,EAAE,gBAAgB,CAAC,KAAK,CAAC,QAAQ,CAAC;YACtC,GAAG,CAAC,KAAK,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAC,aAAa,EAAE,KAAK,CAAC,IAAI,EAAC,CAAC,CAAC,CAAC,EAAE,CAAC;YAChE,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAC,QAAQ,EAAE,KAAK,CAAC,QAAQ,EAAC,CAAC,CAAC,CAAC,EAAE,CAAC;YACrD,GAAG,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,EAAC,oBAAoB,EAAE,KAAK,CAAC,UAAU,EAAC,CAAC,CAAC,CAAC,EAAE,CAAC;SACtE,CAAC,CAAC;QACH,OAAO;YACL,EAAE,EAAE,QAAQ,CAAC,EAAE;YACf,IAAI,EAAE,QAAQ,CAAC,KAAK;YACpB,GAAG,CAAC,QAAQ,CAAC,UAAU,EAAE,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,EAAC,IAAI,EAAE,QAAQ,CAAC,UAAU,CAAC,QAAQ,EAAC,CAAC,CAAC,CAAC,EAAE,CAAC;YAC5F,GAAG,CAAC,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC,CAAC,EAAC,GAAG,EAAE,QAAQ,CAAC,MAAM,CAAC,QAAQ,EAAC,CAAC,CAAC,CAAC,EAAE,CAAC;SACtE,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,qBAAqB,CAAC,IAAqB;QAC/C,OAAO,CAAC,MAAM,IAAI,CAAC,MAAM,CAAC,eAAe,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC;YACvE,EAAE,EAAE,UAAU,CAAC,EAAE;YACjB,IAAI,EAAE,UAAU,CAAC,KAAK;YACtB,GAAG,CAAC,UAAU,CAAC,UAAU,EAAE,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,EAAC,IAAI,EAAE,UAAU,CAAC,UAAU,CAAC,QAAQ,EAAC,CAAC,CAAC,CAAC,EAAE,CAAC;YAChG,GAAG,CAAC,UAAU,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC,CAAC,EAAC,GAAG,EAAE,UAAU,CAAC,MAAM,CAAC,QAAQ,EAAC,CAAC,CAAC,CAAC,EAAE,CAAC;SAC1E,CAAC,CAAC,CAAC;IACN,CAAC;IAED,KAAK,CAAC,UAAU,CAAC,IAAqB;QACpC,OAAO,eAAe,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,MAAM,EAAE,MAAM,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;IACxF,CAAC;IAED,mBAAmB,CAAC,IAAqB,EAAE,KAAa,EAAE,MAAe;QACvE,OAAO,WAAW,MAAM,CAAC,CAAC,CAAC,eAAe,MAAM,GAAG,CAAC,CAAC,CAAC,EAAE,+BAA+B,IAAI,CAAC,KAAK,oBAAoB,KAAK,2BAA2B,CAAC;IACxJ,CAAC;IAED,uBAAuB,CAAC,QAA0B,EAAE,KAAa,EAAE,KAAc;QAC/E,OAAO,KAAK;YACV,CAAC,CAAC,qBAAqB,KAAK,iCAAiC,QAAQ,CAAC,IAAI,gBAAgB;YAC1F,CAAC,CAAC,wCAAwC,QAAQ,CAAC,IAAI,wCAAwC,KAAK,yCAAyC,CAAC;IAClJ,CAAC;CACF"}
@@ -0,0 +1,3 @@
1
+ import type { AppConfig, ConnectionProfile } from '../config.js';
2
+ import type { DestinationAdapter, SourceAdapter } from '../domain.js';
3
+ export declare function createProviderAdapter(profile: ConnectionProfile, config: AppConfig): SourceAdapter & DestinationAdapter;
@@ -0,0 +1,11 @@
1
+ import { createConfluenceClient } from '../clients/confluence-factory.js';
2
+ import { YandexWikiClient } from '../clients/yandex-wiki.js';
3
+ import { ConfluenceAdapter } from './confluence.js';
4
+ import { YandexAdapter } from './yandex.js';
5
+ export function createProviderAdapter(profile, config) {
6
+ if (profile.type === 'yandex-wiki') {
7
+ return new YandexAdapter(profile, new YandexWikiClient(profile, config.timeoutMs, profile.limits));
8
+ }
9
+ return new ConfluenceAdapter(profile, createConfluenceClient(profile, config.timeoutMs));
10
+ }
11
+ //# sourceMappingURL=factory.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"factory.js","sourceRoot":"","sources":["../../src/adapters/factory.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,sBAAsB,EAAC,MAAM,kCAAkC,CAAC;AACxE,OAAO,EAAC,gBAAgB,EAAC,MAAM,2BAA2B,CAAC;AAG3D,OAAO,EAAC,iBAAiB,EAAC,MAAM,iBAAiB,CAAC;AAClD,OAAO,EAAC,aAAa,EAAC,MAAM,aAAa,CAAC;AAE1C,MAAM,UAAU,qBAAqB,CAAC,OAA0B,EAAE,MAAiB;IACjF,IAAI,OAAO,CAAC,IAAI,KAAK,aAAa,EAAE,CAAC;QACnC,OAAO,IAAI,aAAa,CAAC,OAAO,EAAE,IAAI,gBAAgB,CAAC,OAAO,EAAE,MAAM,CAAC,SAAS,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC;IACrG,CAAC;IACD,OAAO,IAAI,iBAAiB,CAAC,OAAO,EAAE,sBAAsB,CAAC,OAAO,EAAE,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC;AAC3F,CAAC"}